﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;
using FreeImageAPI;

namespace Imagenator.Controls
{
	partial class SaveControl : UserControl, ISaveControl
	{
		FREE_IMAGE_FORMAT outputFormat;

		public SaveControl()
		{
			InitializeComponent();
		}

		public virtual Control Control { get { return this; } }

		protected int MaxImageSize { get;private set;}
		protected FREE_IMAGE_TYPE OutputType { get;private set;}
		protected bool AlwaysConvertType { get;private set;}
		protected FREE_IMAGE_SAVE_FLAGS SaveFlags{get;private set;}
		protected FREE_IMAGE_FILTER ResizeFilter { get; private set; }

		protected virtual FREE_IMAGE_SAVE_FLAGS GetSaveFlags() { return FREE_IMAGE_SAVE_FLAGS.DEFAULT; }

		protected override void OnLoad(EventArgs e)
		{
			Settings settings = Settings.Load();
			this.nudSize.Value = new decimal(settings.OutputSize);
			this.cbFilter.Select(settings.ResizingAlgorithm);
			this.cbImageType.Select(settings.OutputType);
			this.cbConvertType.Checked = !settings.AlwaysConvertImageType;

			base.OnLoad(e);
		}

		public virtual void Close()
		{
			Settings settings = Settings.Load();
			settings.OutputSize = (int)this.nudSize.Value;
			settings.ResizingAlgorithm = this.cbFilter.SelectedItem;
			if (this.cbImageType.SelectedIndex > -1)
				settings.OutputType = this.cbImageType.SelectedItem;
			settings.AlwaysConvertImageType = !this.cbConvertType.Checked;
		}

		protected FREE_IMAGE_FORMAT GetOutputFormat(FreeImageBitmap image)
		{
			if (this.outputFormat == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
				return image.ImageFormat;
			return this.outputFormat;
		}

		public virtual void SetFormat(FREE_IMAGE_FORMAT format)
		{
			this.outputFormat = format;
			this.cbImageType.SetFormat(format);
		}

		public virtual bool BeginSaving()
		{
			this.ResizeFilter = this.cbFilter.SelectedItem;
			this.MaxImageSize = (int)this.nudSize.Value;
			if (this.cbImageType.SelectedIndex < 0)
				this.OutputType = FREE_IMAGE_TYPE.FIT_UNKNOWN;
			else
				this.OutputType = this.cbImageType.SelectedItem;
			this.AlwaysConvertType = !this.cbConvertType.Checked;
			this.SaveFlags = this.GetSaveFlags();
			return true;
		}

		public virtual void SaveImage(FreeImageBitmap image, FileInfo srcFile, FileInfo destFile, ArgusLib.Controls.ProgressBox.ThreadState threadState)
		{
			FREE_IMAGE_FORMAT format = this.GetOutputFormat(image);
			bool modified = this.ModifyImage(image, threadState);

			if (this.outputFormat != FREE_IMAGE_FORMAT.FIF_UNKNOWN || modified || srcFile == null || !srcFile.Exists)
			{
				using (FileStream fileStream = destFile.OpenWrite())
				{
					this.SaveImage(image,fileStream, threadState);
				}
			}
			else
			{
				srcFile.CopyTo(destFile.FullName);
			}
			threadState.SendOutput(destFile.FullName + ": Saved");
		}

		protected virtual void SaveImage(FreeImageBitmap image, Stream stream, ArgusLib.Controls.ProgressBox.ThreadState threadState)
		{
			FREE_IMAGE_FORMAT format = this.GetOutputFormat(image);
			bool modified = this.ModifyImage(image, threadState);
			if (!FreeImage.FIFSupportsExportType(format, image.ImageType))
			{
				throw new InvalidOperationException(string.Format("Type {0} is not supported by format {1}", image.ImageType, format));
			}
			image.Save(stream, format, this.SaveFlags);
		}

		public void SaveImage(FreeImageBitmap image, Stream stream)
		{
			this.SaveImage(image, stream, null);
		}

		public virtual void EndSaving()
		{
		}

		protected virtual bool ModifyImage(FreeImageBitmap image, ArgusLib.Controls.ProgressBox.ThreadState threadState)
		{
			bool resized = this.ResizeImage(image, threadState);
			bool converted = this.ConvertImageType(image, threadState);
			return resized || converted;
		}

		protected virtual bool ResizeImage(FreeImageBitmap image, ArgusLib.Controls.ProgressBox.ThreadState threadState)
		{
			if (this.MaxImageSize > 0 && (image.Width > MaxImageSize || image.Height > MaxImageSize))
			{
				Size size = new Size(MaxImageSize, MaxImageSize);
				size = size.ChangeRatio(image.Size.GetRatio(), ArgusLib.Drawing.ChangeRatioOptions.DecreaseAreaSize);
				image.Rescale(size, this.ResizeFilter);
				return true;
			}
			return false;
		}

		protected virtual bool ConvertImageType(FreeImageBitmap image, ArgusLib.Controls.ProgressBox.ThreadState threadState)
		{
			FREE_IMAGE_FORMAT format = this.GetOutputFormat(image);
			if (format != image.ImageFormat)
			{
				if (this.AlwaysConvertType == true || !FreeImage.FIFSupportsExportType(format, image.ImageType))
				{
					if (image.ImageType != FREE_IMAGE_TYPE.FIT_BITMAP && this.OutputType == FREE_IMAGE_TYPE.FIT_BITMAP)
					{
						image.TmoDrago03(1, 0);
						//image.TmoReinhard05(0, 0);
					}
					else
					{
						image.ConvertType(this.OutputType, true);
					}
					return true;
				}
			}
			return false;
		}
	}
}
